package com.gjy.concurrency.beautiful;

import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.concurrent.locks.StampedLock;

/**
 * @author 宫静雨
 * @version 1.0
 * @since 2023-06-13 10:56:52
 */
public class LockTest {

    @Test
    public void test1() {
        StampedLock lock = new StampedLock();
    }

    public static final class Point {
        private BigDecimal x, y;
        private final StampedLock lock = new StampedLock();

        public void move(BigDecimal deltaX, BigDecimal deltaY) {
            long stamp = lock.writeLock();
            try {
                x = x.add(deltaX);
                y = y.add(deltaY);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlockWrite(stamp);
            }
        }

        public BigDecimal distanceFromOrigin() {
            long stamp = lock.tryOptimisticRead();
            BigDecimal currentX = x, currentY = y;
            if (!lock.validate(stamp)) {
                stamp = lock.readLock();
                try {
                    currentY = y;
                    currentX = x;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlockRead(stamp);
                }
            }
            BigDecimal my = currentY.multiply(currentY);
            BigDecimal mx = currentX.multiply(currentX);

            BigDecimal decimal = mx.add(my);
            return BigDecimal.valueOf(Math.sqrt(decimal.doubleValue()));
        }

        public void moveIfAtOrigin(BigDecimal newX, BigDecimal newY) {
            long stamp = lock.readLock();
            try {
                while (x.equals(BigDecimal.valueOf(0.0)) &&
                        y.equals(BigDecimal.valueOf(0.0))) {
                    long ws = lock.tryConvertToWriteLock(stamp);
                    if (ws != 0L) {
                        stamp = ws;
                        x = newX;
                        y = newY;
                        break;
                    } else {
                        lock.unlockRead(stamp);
                        stamp = lock.writeLock();
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock(stamp);
            }
        }

    }
}
